#include "mediaSerialProtocol.h"
#include "log.h"
#include "gpio.h"


extern "C" int MEDIA_kvmTest(){
    if(Media::mediaSerialProtocol::instance()->serialProtocolInit() && Media::mediaSerialProtocol::instance()->serialTestKvm()){
        return 0;
    }
    return -1;
}



namespace Media{

mediaSerialProtocol*     mediaSerialProtocol::sm_instance;
std::mutex 		         mediaSerialProtocol::sm_insMutex;

mediaSerialProtocol *mediaSerialProtocol::instance()
{
	if(sm_instance == NULL)
    {
        std::lock_guard<std::mutex> guard(sm_insMutex);
        if(sm_instance == NULL)
        {
            sm_instance = new mediaSerialProtocol();
        }
    }
    return sm_instance;
}

mediaSerialProtocol::mediaSerialProtocol() 
{ 

}

bool mediaSerialProtocol::serialProtocolInit()
{
    LOG_PrintWarn("start enter \n");
    
    int ret = 0;
    bool result = false;
    CommPortDesc desc;
    memset(&desc, 0, sizeof(desc));

	desc.port = PORT_KVM;
    if(createCommPort(&desc, &m_pCommPortKvm) != 0) //创建串口对象
    {
        LOG_PrintError("Fail to createCommPort:%d !\n", desc.port);
        return false;
    }

    ret = m_pCommPortKvm->open(m_pCommPortKvm);// 打开串口ttyS3
	if(ret < 0)
	{
        LOG_PrintError("Fail to open commport:%d !\n", desc.port);
        return false;
	}

    CommAttribute commAttr = {0};
	commAttr.baudrate = 115200;
    commAttr.dataBits = 8;
    commAttr.parity = commNoParity;
    commAttr.stopBits = commOneStopBit;  

    result = serialSetAttribute(m_pCommPortKvm, commAttr);

    LOG_PrintWarn("start leave \n");

    return result;
}


bool mediaSerialProtocol::serialSetAttribute(CommPort*          pCommPort, CommAttribute attr)
{
     if( pCommPort && (pCommPort->setAttribute(pCommPort, &attr) == 0)) 
     {
        return true;
     }
     
     LOG_PrintError("Fail to serialSetAttribute!\n");
     return false;
}

bool mediaSerialProtocol::serialPortWrite(void* buf, ulong len, int port)
{
    CommPort *pCommPort = NULL;
    int writeLen = -1;
    
    if(port == PORT_KVM)
    {
        pCommPort = m_pCommPortKvm;
    }

    if(pCommPort)
    {
        writeLen = pCommPort->write(pCommPort, buf, len);
    	if(writeLen <= 0)
    	{
             LOG_PrintError("Comm write failed!\n");
             return false;
    	}

    	LOG_PrintWarn("serialPortWrite writeLen=%d\n", writeLen);
    }

    return true;
   
}

bool mediaSerialProtocol::serialPortRead(void* buf, ulong len, int port)
{
    CommPort *pCommPort = NULL;
    int readLen = -1;
    
    if(port == PORT_KVM)
    {
        pCommPort = m_pCommPortKvm;
    }

    if(pCommPort)
    {
        readLen = pCommPort->read(pCommPort, buf, len);
    	if(readLen <= 0)
    	{
             //LOG_PrintError("Comm read failed!\n");
             return false;
    	}

    	LOG_PrintWarn("serialPortRead readLen:%d\n", readLen);

        char* data  = (char*)buf;
    	printf("PortRead buf=\n");
        for(int i = 0; i < readLen; i++)
        {
            printf("%02x ", data[i]);
        }
        printf("\n");

    }

    return true;
   
}

void mediaSerialProtocol::ThreadProc(Fdt::Thread *thread)
{
    thread->setPriority(Fdt::PRIORITY_NORMAL, Fdt::POLICY_RR);

    unsigned char rcvBuf[1024] = {0};
    ulong rcvLen = 1024;

    while(thread->running())
    {
        memset(rcvBuf, 0, sizeof(rcvBuf));
        
        serialPortRead(rcvBuf, rcvLen, PORT_KVM);
        
        usleep(100*1000);
    }


    return;
}



bool mediaSerialProtocol::serialTestKvm()
{
    LOG_PrintWarn("serialTestKvm enter \n");
#if 1
    int level = 1;
    int keyGpio = 105;

    GPIO_Get(keyGpio);
    GPIO_SetDir(keyGpio, 1);
    GPIO_SetLevel(keyGpio, level);
    GPIO_Put(keyGpio);    

    keyGpio = 106;
    GPIO_Get(keyGpio);
    GPIO_SetDir(keyGpio, 1);
    GPIO_SetLevel(keyGpio, level);
    GPIO_Put(keyGpio);
    
    keyGpio = 104;
    GPIO_Get(keyGpio);
    GPIO_SetDir(keyGpio, 1);
    GPIO_SetLevel(keyGpio, level);
    GPIO_Put(keyGpio);

    sleep(1);
    level = 0;
    GPIO_Get(keyGpio);
    GPIO_SetLevel(keyGpio, level);
    GPIO_Put(keyGpio);

    sleep(1);
    
#endif 
    bool result = false;
    
    /*m_thread.start([this](Fdt::Thread *thread){this->ThreadProc(thread);}); //启动单独线程处理流
    
    unsigned char testVesion[3] = {0x57, 0xAB, 0x87};

    result = serialPortWrite(testVesion, sizeof(testVesion), PORT_KVM);
    if(!result)
    {
        return false;
    }*/
    
    unsigned char status_request_cmd[8] = {0x57, 0xab, 0x82, 0xa3, 0x57, 0xab, 0x82, 0xa3};

    result = serialPortWrite(status_request_cmd, sizeof(status_request_cmd), PORT_KVM);
    if(!result)
    {
        return false;
    }

    unsigned char work_status_change_01[4] = {0x57, 0xAB, 0x85, 0x0};

    result = serialPortWrite(work_status_change_01, sizeof(work_status_change_01), PORT_KVM);
    if(!result)
    {
        return false;
    }

    unsigned char connect[150] = { 
	0x57 , 0xab , 0x81 , 0x0  , 0x85 , 0x0  , 0x5  , 0x1  , 0x9  , 0x6  , 0xa1 , 0x1  , 0x85 , 0x1  , 0x5  , 
	0x7  , 0x19 , 0xe0 , 0x29 , 0xe7 , 0x15 , 0x0  , 0x25 , 0x1  , 0x75 , 0x1  , 0x95 , 0x8  , 0x81 , 0x2  , 
	0x95 , 0x1  , 0x75 , 0x8  , 0x81 , 0x1  , 0x95 , 0x5  , 0x75 , 0x1  , 0x5  , 0x8  , 0x19 , 0x1  , 0x29 , 
	0x5  , 0x91 , 0x2  , 0x95 , 0x1  , 0x75 , 0x3  , 0x91 , 0x1  , 0x95 , 0x6  , 0x75 , 0x8  , 0x15 , 0x0  , 
	0x26 , 0xff , 0x0  , 0x5  , 0x7  , 0x19 , 0x0  , 0x2a , 0xff , 0x0  , 0x81 , 0x0  , 0x5  , 0xc  , 0x9  , 
	0x0  , 0x15 , 0x80 , 0x25 , 0x7f , 0x75 , 0x8  , 0x95 , 0x8  , 0xb1 , 0x2  , 0xc0 , 0x5  , 0xc  , 0x9  , 
	0x1  , 0xa1 , 0x1  , 0x85 , 0x2  , 0x19 , 0x0  , 0x2a , 0x3c , 0x2  , 0x15 , 0x0  , 0x26 , 0x3c , 0x2  ,
    0x95 , 0x1  , 0x75 , 0x10 , 0x81 , 0x0  , 0xc0 , 0x5  , 0x1  , 0x9  , 0x80 , 0xa1 , 0x1  , 0x85 , 0x3  , 
	0x19 , 0x81 , 0x29 , 0x83 , 0x15 , 0x0  , 0x25 , 0x1  , 0x75 , 0x1  , 0x95 , 0x3  , 0x81 , 0x2  , 0x95 , 
	0x5  , 0x81 , 0x1  , 0xc0 , 0x4a , 0x56 , 0x32 };

	result = serialPortWrite(connect, sizeof(connect), PORT_KVM);
    if(!result)
    {
        return false;
    }

	unsigned char testSequence[17][16] = {
		{ 0x57, 0xab, 0x83, 0xc , 0x12, 0x1 , 0x0 , 0x0 , 0x00, 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x01}, //up
		{ 0x57, 0xab, 0x83, 0xc , 0x12, 0x1 , 0x0 , 0x0 , 0x17, 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x1 , 0x19}, //t
		{ 0x57, 0xab, 0x83, 0xc , 0x12, 0x1 , 0x0 , 0x0 , 0x00, 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x2 , 0x03}, //up
		{ 0x57, 0xab, 0x83, 0xc , 0x12, 0x1 , 0x0 , 0x0 , 0x08, 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x3 , 0x0c}, //e
		{ 0x57, 0xab, 0x83, 0xc , 0x12, 0x1 , 0x0 , 0x0 , 0x00, 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x4 , 0x05}, //up
		{ 0x57, 0xab, 0x83, 0xc , 0x12, 0x1 , 0x0 , 0x0 , 0x16, 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x5 , 0x1c}, //s
		{ 0x57, 0xab, 0x83, 0xc , 0x12, 0x1 , 0x0 , 0x0 , 0x00, 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x6 , 0x07}, //up
		{ 0x57, 0xab, 0x83, 0xc , 0x12, 0x1 , 0x0 , 0x0 , 0x17, 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x7 , 0x1f}, //t
		
		{ 0x57, 0xab, 0x83, 0xc , 0x12, 0x1 , 0x0 , 0x0 , 0x00, 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x8 , 0x09}, //up
		{ 0x57, 0xab, 0x83, 0xc , 0x12, 0x1 , 0x0 , 0x0 , 0x2c, 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x9 , 0x36}, //space
		
		{ 0x57, 0xab, 0x83, 0xc , 0x12, 0x1 , 0x0 , 0x0 , 0x00, 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0xa , 0x0b}, //up		
		{ 0x57, 0xab, 0x83, 0xc , 0x12, 0x1 , 0x0 , 0x0 , 0x12, 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0xb , 0x1e}, //o
		{ 0x57, 0xab, 0x83, 0xc , 0x12, 0x1 , 0x0 , 0x0 , 0x00, 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0xc , 0x0d}, //up
		{ 0x57, 0xab, 0x83, 0xc , 0x12, 0x1 , 0x0 , 0x0 , 0x0e, 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0xd , 0x1c}, //k
		
		{ 0x57, 0xab, 0x83, 0xc , 0x12, 0x1 , 0x0 , 0x0 , 0x00, 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0xe , 0x0f}, //up		
		{ 0x57, 0xab, 0x83, 0xc , 0x12, 0x1 , 0x0 , 0x0 , 0x28, 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0xf , 0x38}, //enter
		{ 0x57, 0xab, 0x83, 0xc , 0x12, 0x1 , 0x0 , 0x0 , 0x00, 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x10 , 0x11}, //up

		
	};

	sleep(1);

	for (int j = 0; j < 1; j++)
	{

    	for (int i = 0; i < 17; i++)
    	{
    		result = serialPortWrite(testSequence[i], 16, PORT_KVM);
            if(!result)
            {
                return false;
            }
    		usleep(100);
    	}
	}

	LOG_PrintWarn("serialTestKvm success \n");
    
    

    return true;
}



}

